package main

import "fmt"

/*
继承
当多个结构体存在相同的属性(字段)和方法时,可以从这些结构体中抽象出结构体,在该结构体中定义这些相同的属性和方法
其他结构体不需要重新定义这些属性和方法,只需要嵌套一个匿名结构体即可.也就是说在golang中,如果一个struct嵌套了
另一个匿名结构体,那么这个结构体可以直接访问匿名结构体的字段和方法,从而实现了继承的特性

1.结构体可以使用嵌套匿名结构体所有的字段和方法,即:首字母大写或者小写的字段,方法都可以使用
2.匿名结构体字段访问可以简化
3.当结构体和匿名结构体有相同的字段或者方法时,编译器采用就近访问原则访问,如希望访问匿名结构体的字段和方法
可以通过匿名结构体名来区分
4.(不推荐使用)golang中支持多继承,如一个结构体嵌套了多个匿名结构体,那么该结构体可以直接访问嵌套的匿名结构体的字段和方法
从而实现了多重继承. 为了保证代码的简洁性,建议尽量不使用多重继承,很多语言已将多重继承去除了
5.如嵌入的匿名结构体有相同的字段名或者方法名,则在访问时,需要通过匿名结构体的类型名来区分
6.结构体的匿名字段是基本数据类型
7.嵌套匿名结构体后,也可以在创建结构体变量(实例)时,直接指定各个匿名结构体字段的值
8.嵌入匿名结构体的指针也是可以的
9.结构体的字段可以是结构体类型的(组合模式)
*/

type A struct {
	x int
	a string
}

type B struct {
	x int
	b string
}

type C struct {
	A
	B
	c int
}

type D struct {
	//继承模式, 不引入变量名
	*A
	//引入变量名, 为组合模式
	tb *B
	int
}

func main() {
	//构建C结构体实例
	testStructC()
	fmt.Println("----------------------")
	testStructD()
}

func testStructD() {
	d := D{&A{10, "A结构体"},
		&B{21, "B结构体"},
		88}
	fmt.Println(d)
	fmt.Println(d.A)
	fmt.Println(*d.A)
	fmt.Println(d.tb)
	fmt.Println(*d.tb)
	fmt.Println(d.a)
	fmt.Println(d.A.x)
	fmt.Println(d.tb.x)
}

func testStructC() {
	c := C{A{10, "A结构体"}, B{21, "B结构体"}, 88}
	fmt.Println(c)
	fmt.Println(c.a)
	fmt.Println(c.A.x)
	fmt.Println(c.B.x)
	fmt.Println(c.c)
}
